package routefinder.module;

import java.util.ArrayList;
import java.util.HashMap;

public class RouteStoreAilin extends RouteStore {

	private ArrayList<Vertex> locationsList;
	private HashMap<String, Vertex> locationsMap;
	private HashMap<String, ArrayList<Edge>> pathsMap;
	private HashMap<String, Integer> indices;
	private double[][] cost;
	private boolean built;

	public RouteStoreAilin() {
		this.locationsList = new ArrayList<Vertex>();
		this.locationsMap = new HashMap<String, Vertex>();
		this.pathsMap = new HashMap<String, ArrayList<Edge>>();
		this.indices = new HashMap<String, Integer>();
		this.built = false;
	}

	public boolean addLocation(String locationName) {
		Vertex v = new Vertex(locationName);

		if (!this.locationsMap.containsKey(locationName)) {
			this.locationsMap.put(locationName, v);
			this.locationsList.add(v);
			this.built = false;
			this.indices.put(v.getName(), this.locationsList.size() - 1);
			return true;
		} else {
			return false;
		}
	}

	public boolean addPath(String fromLocation, String toLocation,
			double distance) {

		Vertex a = this.locationsMap.get(fromLocation);
		Vertex b = this.locationsMap.get(toLocation);

		if ((a != null) && (b != null)) {

			Edge e = new Edge(a, b, distance);

			ArrayList<Edge> temp = this.pathsMap.get(fromLocation);
			ArrayList<Edge> temp2 = this.pathsMap.get(toLocation);

			if (temp == null) {
				this.pathsMap.put(fromLocation, new ArrayList<Edge>());
				temp = this.pathsMap.get(fromLocation);
			}
			if (temp2 == null) {
				this.pathsMap.put(toLocation, new ArrayList<Edge>());
				temp2 = this.pathsMap.get(toLocation);
			}

			if (!temp.contains(e)) {
				temp.add(e);
				temp2.add(e);
				this.built = false;
				return true;
			} else {
				return false;
			}

		} else {
			return false;
		}

	}

	public double getShortestDistance(String fromLocation, String toLocation) {
		try
		{
		int fromIndex = this.indices.get(fromLocation);
		int toIndex = this.indices.get(toLocation);
		
		if (!this.built) {
			this.cost = new double[this.locationsList.size()][this.locationsList
					.size()];
			for (int i = 0; i < this.locationsList.size(); i++) {
				for (int j = 0; j < this.locationsList.size(); j++) {
					this.cost[i][j] = -1;
				}
			}
			for (int i = 0; i < this.locationsList.size(); i++) {
				Vertex v = this.locationsList.get(i);
				ArrayList<Edge> edges = this.pathsMap.get(v.getName());
				for (int j = 0; j < this.locationsList.size(); j++) {
					Vertex t = this.locationsList.get(j);
					for (Edge e : edges) {
						if ((e.getA().equals(t) || e.getB().equals(t))) {
							this.cost[i][j] = e.getCost();
						}
					}
				}
			}
			this.search();
			this.built = true;
			return this.cost[fromIndex][toIndex];
		}
		}
		catch(Exception ex)
		{
			return -1;
		}
		return -1;
	}

	private void search() {
		for (int k = 0; k < locationsList.size(); k++) {
			for (int i = 0; i < locationsList.size(); i++) {
				for (int j = 0; j < locationsList.size(); j++) {

					if ((this.cost[i][k] + this.cost[k][j] < this.cost[i][j])
							|| (this.cost[i][j] == -1)) {
						cost[i][j] = cost[i][k] + cost[k][j];
					}

				}
			}
		}
	}
}
